﻿using System;
using System.Collections.Concurrent;
using System.IO;
using Microsoft.Scripting.Hosting;
using IronPython.Hosting;
using Development.Tools;
using System.Reflection;

namespace Development.Script
{
    /// <summary>
    /// py 速度最快
    /// </summary>
    public class PyRunTime:Singleton<PyRunTime>,IScriptRunTime,IDisposable
    {
        private readonly string _codeName = "Py";
        private ConcurrentDictionary<string, dynamic> _scopes = new ConcurrentDictionary<string, dynamic>();
        private FileSystemWatcher _fileWatcher = null;
        private ScriptRuntime _runTime = null;

        public void LoadScript()
        {
            _runTime = Python.CreateRuntime();
            var files = ScriptUtil.GetScriptFiles(_codeName);
            foreach(var f in files)
            {
                string scopeName = Path.GetFileNameWithoutExtension(f);
                dynamic scope = _runTime.ExecuteFile(f);
                _scopes.TryAdd(scopeName, scope);
            }
            AddFileWatcher(ScriptUtil.GetScriptPath(_codeName), "*.py");

        }

        private void AddFileWatcher(string path, string filter)
        {
            if (_fileWatcher == null)
            {
                _fileWatcher = new FileSystemWatcher(path, filter);
                _fileWatcher.Changed += watcher_Changed;
                _fileWatcher.EnableRaisingEvents = true;
            }
        }

        void watcher_Changed(object sender, FileSystemEventArgs e)
        {
            string scopeName = Path.GetFileNameWithoutExtension(e.FullPath);
            try
            {

                dynamic scope = _runTime.ExecuteFile(e.FullPath);
                if (_scopes.ContainsKey(scopeName))
                {
                    _scopes[scopeName] = scope;
                }
                else
                {
                    _scopes.TryAdd(scopeName, scope);
                }
                Log.WriteLog(ELogLevel.LOG_INFO, "reload py name=" + scopeName);

            }
            catch(Exception ex)
            {
                Log.WriteLog(ELogLevel.LOG_ERROR, ex.Message);
            }
        }

        public dynamic GetScope(string scriptCode)
        {
            if (_scopes.ContainsKey(scriptCode))
            {
                return _scopes[scriptCode];
            }
            return null;
        }

        public object Invoke(string scope, string functionName, params object[] args)
        {
            return null;
        }

        public dynamic GetVariable(string scopeName, string VariableName)
        {
            ScriptScope sc = GetScope(scopeName);
            if(sc != null)
            {
                return sc.GetVariable(VariableName);
            }
            return null;
        }

        public void Dispose()
        {
            if (_fileWatcher != null)
            {
                _fileWatcher.Dispose();
                _scopes.Clear();
            }
        }
    }
}
